package v1

import (
	"gomicrov4-sharemod/gateway-api/controllers"
	"gomicrov4-sharemod/gateway-api/utils"
	"gomicrov4-sharemod/services/user-service/proto/params"
	"gomicrov4-sharemod/services/user-service/proto/user"
	"strconv"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/google/uuid"
)

/*
 +----------------------------------------------------------------------
 + Title        : UserController
 + Author       : huwl
 + Version      : 1.0.0
 + Initial-Time : 2019-08-08
 + Last-time    : 这个文件最后修改的时间 + 修改人的名称
 + Desc         : 用户控制器
 +----------------------------------------------------------------------
*/
type UserController struct {
	controllers.BaseController
}

/**
 * 用户名登录
 *
 * @param string username ----------------------必传,用户名
 * @param string password ----------------------必传,密码
 * @param string captcha -----------------------必传,验证码
 * @param string captcha_id --------------------必传,验证码ID
 * @return Json
 * @author huwl
 */
func (control UserController) Login(ctx *gin.Context) {
	username := ctx.DefaultPostForm("username", "")
	password := ctx.DefaultPostForm("password", "")
	// captcha := ctx.DefaultPostForm("captcha", "")
	// captchaId := ctx.DefaultPostForm("captcha_id", "")

	if username == "" {
		control.BaseError(ctx, control.WithMessage("请输入用户名"))
		return
	}
	if password == "" {
		control.BaseError(ctx, control.WithMessage("请输入密码"))
		return
	}

	//base64Captcha版
	// b := utils.ValidateCaptcha(captchaId, captcha)
	// if !b {
	// 	control.BaseError(ctx, "验证码错误")
	// 	return
	// }

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	userResult, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Username: username,
		Status:   "1",
	})

	if err != nil || !utils.CompareBcrypt(userResult.User.Password, password) {
		control.BaseError(ctx, control.WithMessage("用户名或者密码错误"))
		return
	}

	token, err := utils.GenerateToken(strconv.Itoa(int(userResult.User.Uid)))
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 生成refreshToken
	refreshToken := uuid.New().String()
	// 需要将refreshToken存入redis
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	err = ri.RedisSet("userRefreshToken:"+strconv.Itoa(int(userResult.User.Uid)), refreshToken, time.Hour*12*10)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(gin.H{
		"user":              userResult.User,
		"token":             token,
		"token_expire_time": time.Now().Add(utils.TokenExpireTime).Unix(),
		"refresh_token":     refreshToken,
	}), control.WithMessage("登录成功"))
}

/**
 * 手机号登录
 *
 * @param string mobile ------------------------必传,手机号
 * @param string code --------------------------必传,验证码
 * @return Json
 * @author huwl
 */
func (control UserController) MobileLogin(ctx *gin.Context) {
	mobile := ctx.DefaultPostForm("mobile", "")
	code := ctx.DefaultPostForm("code", "")

	if mobile == "" {
		control.BaseError(ctx, control.WithMessage("请输入手机号"))
		return
	}
	if !utils.CheckMobile(mobile) {
		control.BaseError(ctx, control.WithMessage("请输入格式正确的手机号"))
		return
	}
	if code == "" {
		control.BaseError(ctx, control.WithMessage("请输入验证码"))
		return
	}

	// 校验验证码
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	redisCode, _ := ri.RedisGet("login_code_" + mobile)
	if redisCode != code {
		control.BaseError(ctx, control.WithMessage("验证码错误"))
		return
	}

	// 获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	userResult, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Mobile: mobile,
		Status: "1",
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage("用户信息错误"))
		return
	}

	// 生成token
	token, err := utils.GenerateToken(strconv.Itoa(int(userResult.User.Uid)))
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 生成refreshToken
	refreshToken := uuid.New().String()
	// 需要将refreshToken存入redis
	err = ri.RedisSet("uid_"+strconv.Itoa(int(userResult.User.Uid)), refreshToken, time.Hour*12*10)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(gin.H{
		"user":              userResult.User,
		"token":             token,
		"token_expire_time": time.Now().Add(utils.TokenExpireTime).Unix(),
		"refresh_token":     refreshToken,
	}), control.WithMessage("登录成功"))
}

/**
 * 发送验证码
 *
 * @param string mobile ------------------------必传,手机号
 * @return Json
 * @author huwl
 */
func (control UserController) LoginSendCode(ctx *gin.Context) {
	mobile := ctx.DefaultPostForm("mobile", "")
	if mobile == "" {
		control.BaseError(ctx, control.WithMessage("请输入手机号"))
		return
	}
	if !utils.CheckMobile(mobile) {
		control.BaseError(ctx, control.WithMessage("请输入格式正确的手机号"))
		return
	}

	// 获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	_, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Mobile: mobile,
		Status: "1",
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage("手机号不存在"))
		return
	}

	// 生成、存储 验证码
	// time.Second*300 过期时间5分钟
	code := utils.CreateRandNum(100000, 400000)
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	err = ri.RedisSet("login_code_"+mobile, code, time.Second*300)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 发送短信
	err = utils.SendSms(mobile, "verificationCodeTemplate", map[string]interface{}{"code": code})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("发送验证码成功"))
}

/**
 * 使用微信绑定的手机号登录
 *
 * @param string code --------------------------必传,动态令牌
 * @return Json
 * @author huwl
 */
func (control UserController) WxMobileLogin(ctx *gin.Context) {
	code := ctx.DefaultPostForm("code", "")
	mobile := ctx.DefaultPostForm("mobile", "17830244248")

	if code == "" {
		control.BaseError(ctx, control.WithMessage("微信用户动态令牌错误"))
		return
	}

	//读取 wx 配置
	cfg, err := utils.GetConfig("wx", "yml")
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 获取接口调用凭据
	tokenResult, err := utils.HttpGet("https://api.weixin.qq.com/cgi-bin/token?", map[string]string{
		"grant_type": "client_credential",
		"appid":      cfg.GetString(utils.Env + ".appid"),
		"secret":     cfg.GetString(utils.Env + ".secret"),
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	errmsg, ok := tokenResult["errmsg"]
	if ok {
		control.BaseError(ctx, control.WithMessage(errmsg.(string)))
		return
	}

	// 获取微信绑定的手机号，必须为非个人且认证过的小程序才能调用该接口
	// url := "https://api.weixin.qq.com/wxa/business/getuserphonenumber"
	// result, err := utils.HttpPostForm(url, map[string]string{
	// 	"access_token": tokenResult["access_token"].(string),
	// 	"code":         code,
	// })
	// if err != nil {
	// 	control.BaseError(ctx, control.WithMessage(err.Error()))
	// 	return
	// }

	// errmsg, ok = result["errmsg"]
	// if ok {
	// 	control.BaseError(ctx, control.WithMessage(errmsg.(string)))
	// 	return
	// }

	// 根据手机号获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	userRes, err := userServiceClient.UserList(ctx, &user.QueryUserRequest{
		// Mobile: result["phone_number"],
		Mobile:   mobile,
		Status:   "all",
		PageSize: -1,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	var userInfo *user.User
	// 判断该手机号是否存在
	if userRes.ListResult.Total > 0 { // 存在则登录成功
		userInfo = userRes.Users[0]
	} else { // 新增用户
		// 生成用户名
		username := utils.GenerateUsername(21)

		// 新增用户
		addUserRes, err := userServiceClient.AddUser(ctx, &user.AddUserRequest{
			Username: username,
			// Mobile:   result["phone_number"],
			Mobile: mobile,
			Status: 1,
		})
		if err != nil {
			control.BaseError(ctx, control.WithMessage(err.Error()))
			return
		}

		userInfo = addUserRes.User
	}

	// 生成token
	token, err := utils.GenerateToken(strconv.Itoa(int(userInfo.Uid)))
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 生成refreshToken
	refreshToken := uuid.New().String()
	// 需要将refreshToken存入redis
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	err = ri.RedisSet("uid_"+strconv.FormatInt(int64(userInfo.Uid), 10), refreshToken, time.Hour*12*10)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(gin.H{
		"user":              userInfo,
		"token":             token,
		"token_expire_time": time.Now().Add(utils.TokenExpireTime).Unix(),
		"refresh_token":     refreshToken,
	}), control.WithMessage("登录成功"))
}

/**
 * QQ登录
 *
 * @param string union_id ----------------------必传,联合ID
 * @return Json
 * @author huwl
 */
func (control UserController) QqLogin(ctx *gin.Context) {
	unionId := ctx.DefaultPostForm("union_id", "")

	if unionId == "" {
		control.BaseError(ctx, control.WithMessage("QQ联合ID"))
		return
	}

	// userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	// userResult, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
	// 	Mobile: mobile,
	// 	Status: "1",
	// })
	// if err != nil {
	// 	control.BaseError(ctx, "用户信息错误")
	// 	return
	// }

	// token, err := utils.GenerateToken(strconv.Itoa(int(userResult.User.Uid)))
	// if err != nil {
	// 	control.BaseError(ctx, control.WithMessage(err.Error()))
	// 	return
	// }

	if unionId != "04EE96B4BF1A3289F9BD389E2CE1B572" {
		control.BaseSuccess(ctx, control.WithCode(211))
		return
	}

	control.BaseSuccess(ctx, control.WithData(gin.H{
		// "user":  userResult.User,
		// "token": token,
	}), control.WithMessage("登录成功"))
}

//退出
func (control UserController) Logout(ctx *gin.Context) {
	err := utils.ClearToken("xxxx")
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	control.BaseSuccess(ctx, control.WithData("退出成功"))
}

/**
 * 刷新token
 *
 * @param string refresh_token -----------------必传,刷新token
 * @return json
 * @author huwl
 */
func (control UserController) RefreshToken(ctx *gin.Context) {
	id, _ := ctx.Get("id")
	uid, _ := strconv.Atoi(id.(string))
	refreshToken := ctx.DefaultPostForm("refresh_token", "")

	if refreshToken == "" {
		control.BaseError(ctx, control.WithCode(407), control.WithMessage("刷新token不能为空"))
		return
	}

	// 获取redis存储的refreshToken
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	cacheRefreshToken, err := ri.RedisGet("uid_" + strconv.Itoa(uid))
	if err != nil {
		if err.Error() == "redis: nil" {
			control.BaseError(ctx, control.WithCode(407), control.WithMessage("刷新token已过期"))
		} else {
			control.BaseError(ctx, control.WithCode(407), control.WithMessage(err.Error()))
		}
		return
	}

	if cacheRefreshToken != refreshToken {
		control.BaseError(ctx, control.WithCode(407), control.WithMessage("刷新token错误"))
		return
	}

	token, err := utils.GenerateToken(strconv.Itoa(uid))
	if err != nil {
		control.BaseError(ctx, control.WithCode(407), control.WithMessage(err.Error()))
		return
	}

	// todo是否需要重新生成 refreshToken,暂时没有重新生成

	control.BaseSuccess(ctx, control.WithData(gin.H{
		"token":             token,
		"token_expire_time": time.Now().Add(utils.TokenExpireTime).Unix(),
		"refresh_token":     refreshToken,
	}), control.WithMessage("刷新token成功"))
}

/**
 * 注册
 *
 * @param string username ----------------------必传,用户名
 * @param string password ----------------------必传,密码
 * @param string repassword --------------------必传,重复密码
 * @param string mobile ------------------------必传,手机号
 * @param string email -------------------------必传,邮箱
 * @param string captcha -----------------------必传,验证码
 * @param string captcha_id --------------------必传,验证码ID
 * @return Json
 * @author huwl
 */
func (control UserController) Register(ctx *gin.Context) {
	username := ctx.DefaultPostForm("username", "")
	password := ctx.DefaultPostForm("password", "")
	repassword := ctx.DefaultPostForm("repassword", "")
	mobile := ctx.DefaultPostForm("mobile", "")
	email := ctx.DefaultPostForm("email", "")
	// captcha := ctx.DefaultPostForm("captcha", "")
	// captchaId := ctx.DefaultPostForm("captcha_id", "")

	if username == "" {
		control.BaseError(ctx, control.WithMessage("请输入用户名"))
		return
	}
	if password == "" {
		control.BaseError(ctx, control.WithMessage("请输入密码"))
		return
	}
	if repassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入确认密码"))
		return
	}
	if password != repassword {
		control.BaseError(ctx, control.WithMessage("两次密码要输入一致哦"))
		return
	}
	if !utils.CheckMobile(mobile) {
		control.BaseError(ctx, control.WithMessage("请输入正确格式的手机号"))
		return
	}
	if !utils.CheckEmail(email) {
		control.BaseError(ctx, control.WithMessage("请输入正确格式的邮箱"))
		return
	}

	//判断验证码
	// b := utils.ValidateCaptcha(captchaId, captcha)
	// if !b {
	// 	control.BaseError(ctx, "验证码错误")
	// 	return
	// }

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	_, err := userServiceClient.AddUser(ctx, &user.AddUserRequest{
		Username: username,
		Password: password,
		Mobile:   mobile,
		Email:    email,
		Status:   1,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("用户注册成功"))
}

/**
 * 编辑用户
 *
 * @param string name --------------------------非必传,姓名
 * @param string nick --------------------------非必传,昵称
 * @param string email -------------------------非必传,邮箱
 * @param string username ----------------------非必传,用户名
 * @param string avatar_url --------------------非必传,头像
 * @param int source ---------------------------非必传,来源
 * @param int level ----------------------------非必传,级别
 * @param int balance --------------------------非必传,余额
 * @param int gender ---------------------------非必传,性别
 * @param int province_id ----------------------非必传,省ID
 * @param int city_id --------------------------非必传,市ID
 * @param int district_id ----------------------非必传,区ID
 * @param string note --------------------------非必传,备注
 * @return Json
 * @author huwl
 */
func (control UserController) Edit(ctx *gin.Context) {
	id, _ := ctx.Get("id")
	uid, _ := strconv.ParseInt(id.(string), 10, 64)
	name := ctx.DefaultPostForm("name", "")
	nick := ctx.DefaultPostForm("nick", "")
	email := ctx.DefaultPostForm("email", "")
	balance, _ := strconv.ParseInt(ctx.DefaultPostForm("balance", "-1"), 10, 64)
	username := ctx.DefaultPostForm("username", "")
	avatarUrl := ctx.DefaultPostForm("avatar_url", "")
	source, _ := strconv.ParseInt(ctx.DefaultPostForm("source", "0"), 10, 64)
	level, _ := strconv.ParseInt(ctx.DefaultPostForm("level", "0"), 10, 64)
	gender, _ := strconv.ParseInt(ctx.DefaultPostForm("gender", "0"), 10, 64)
	provinceId, _ := strconv.ParseInt(ctx.DefaultPostForm("province_id", "0"), 10, 64)
	cityId, _ := strconv.ParseInt(ctx.DefaultPostForm("city_id", "0"), 10, 64)
	districtId, _ := strconv.ParseInt(ctx.DefaultPostForm("district_id", "0"), 10, 64)
	note := ctx.DefaultPostForm("note", "")

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	result, err := userServiceClient.EditUser(ctx, &user.EditUserRequest{
		Uid:        uid,
		Name:       name,
		Nick:       nick,
		Email:      email,
		Balance:    balance,
		Username:   username,
		AvatarUrl:  avatarUrl,
		Source:     uint32(source),
		Level:      uint32(level),
		Gender:     uint32(gender),
		ProvinceId: uint32(provinceId),
		CityId:     uint32(cityId),
		DistrictId: uint32(districtId),
		Note:       note,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(result.Msg))
}

/**
 * 编辑手机号
 *
 * @param string mobile ------------------------必传,手机号
 * @return Json
 * @author huwl
 */
func (control UserController) EditMobile(ctx *gin.Context) {
	id, _ := ctx.Get("id")
	uid, _ := strconv.ParseInt(id.(string), 10, 64)
	mobile := ctx.DefaultPostForm("mobile", "")

	if !utils.CheckMobile(mobile) {
		control.BaseError(ctx, control.WithMessage("请输入正确格式的手机号"))
		return
	}

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	_, err := userServiceClient.EditUser(ctx, &user.EditUserRequest{
		Uid:     uid,
		Mobile:  mobile,
		Balance: -1,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("修改手机号成功"))
}

/**
 * 编辑邮箱
 *
 * @param string email -------------------------必传,邮箱
 * @return Json
 * @author huwl
 */
func (control UserController) EditEmail(ctx *gin.Context) {
	id, _ := ctx.Get("id")
	uid, _ := strconv.ParseInt(id.(string), 10, 64)
	email := ctx.DefaultPostForm("email", "")

	if !utils.CheckEmail(email) {
		control.BaseError(ctx, control.WithMessage("请输入正确格式的邮箱"))
		return
	}

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	_, err := userServiceClient.EditUser(ctx, &user.EditUserRequest{
		Uid:     uid,
		Email:   email,
		Balance: -1,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("修改邮箱成功"))
}

/**
 * 修改密码
 *
 * @param string raw_password ------------------必传,原密码
 * @param string new_password ------------------必传,新密码
 * @param string repassword --------------------必传,确认密码
 * @return Json
 * @author huwl
 */
func (control UserController) ChangePassword(ctx *gin.Context) {
	id, _ := ctx.Get("id")
	uid, _ := strconv.ParseInt(id.(string), 10, 64)
	rawPassword := ctx.DefaultPostForm("raw_password", "")
	newPassword := ctx.DefaultPostForm("new_password", "")
	repassword := ctx.DefaultPostForm("repassword", "")

	if rawPassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入原密码"))
		return
	}
	if newPassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入新密码"))
		return
	}
	if repassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入确认密码"))
		return
	}
	if newPassword != repassword {
		control.BaseError(ctx, control.WithMessage("两次密码要输入一致哦"))
		return
	}

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	result, err := userServiceClient.ChangePassword(ctx, &user.ChangePasswordRequest{
		Uid:         uid,
		RawPassword: rawPassword,
		NewPassword: newPassword,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(result.Msg))
}

/**
 * 编辑用户状态
 *
 * @param string uids --------------------------必传,用户ID支持多个
 * @param int status ---------------------------必传,状态
 * @return Json
 * @author huwl
 */
func (control UserController) EditStatus(ctx *gin.Context) {
	uids := strings.TrimRight(ctx.DefaultQuery("uids", ""), ",")
	status, _ := strconv.ParseInt(ctx.DefaultQuery("uids", ""), 10, 64)

	if uids == "" {
		control.BaseError(ctx, control.WithMessage("用户ID错误"))
		return
	}
	if status == 0 {
		control.BaseError(ctx, control.WithMessage("用户状态错误"))
		return
	}

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	result, err := userServiceClient.EditUserStatus(ctx, &params.EditStatusRequest{Ids: uids, Status: int32(status)})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(result.Msg))
}

/**
 * 用户列表
 *
 * @param int uid ------------------------------非必传,用户ID
 * @param string uids --------------------------非必传,用户ID支持多个
 * @param string name --------------------------非必传,姓名
 * @param string nick --------------------------非必传,昵称
 * @param string username ----------------------非必传,用户名
 * @param int source ---------------------------非必传,来源
 * @param int level ----------------------------非必传,级别
 * @param string mobile ------------------------非必传,手机号
 * @param int gender ---------------------------非必传,性别
 * @param int province_id ----------------------非必传,省ID
 * @param int city_id --------------------------非必传,城市ID
 * @param int district_id ----------------------非必传,区ID
 * @param string status ------------------------非必传,状态支持多个：1,-1
 * @param string start_create_time -------------非必传,开始创建时间
 * @param string end_create_time ---------------非必传,结束创建时间
 * @param string sort_field --------------------非必传,排序字段
 * @param string sort_type ---------------------非必传,排序方式
 * @param int page_size ------------------------非必传,条数
 * @param int page -----------------------------非必传,页码
 * @return Json
 * @author huwl
 */
func (control UserController) List(ctx *gin.Context) {
	uid, _ := strconv.ParseInt(ctx.DefaultQuery("uid", "0"), 10, 64)
	uids := strings.TrimRight(ctx.DefaultQuery("uids", ""), ",")
	name := ctx.DefaultQuery("name", "")
	nick := ctx.DefaultQuery("nick", "")
	username := ctx.DefaultQuery("username", "")
	source, _ := strconv.ParseInt(ctx.DefaultQuery("source", "0"), 10, 64)
	level, _ := strconv.ParseInt(ctx.DefaultQuery("level", "0"), 10, 64)
	mobile := ctx.DefaultQuery("mobile", "")
	gender, _ := strconv.ParseInt(ctx.DefaultQuery("gender", "0"), 10, 64)
	provinceId, _ := strconv.ParseInt(ctx.DefaultQuery("province_id", "0"), 10, 64)
	cityId, _ := strconv.ParseInt(ctx.DefaultQuery("city_id", "0"), 10, 64)
	districtId, _ := strconv.ParseInt(ctx.DefaultQuery("district_id", "0"), 10, 64)
	status := ctx.DefaultQuery("status", "all")
	startCreateTime := ctx.DefaultQuery("start_create_time", "")
	endCreateTime := ctx.DefaultQuery("end_create_time", "")
	sortField := ctx.DefaultQuery("sort_field", "uid")
	sortType := ctx.DefaultQuery("sort_type", "desc")
	pageSize, _ := strconv.ParseInt(ctx.DefaultQuery("page_size", "20"), 10, 64)
	page, _ := strconv.ParseInt(ctx.DefaultQuery("page", "1"), 10, 64)

	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	result, err := userServiceClient.UserList(ctx, &user.QueryUserRequest{
		Uid:             uid,
		Uids:            uids,
		Name:            name,
		Nick:            nick,
		Username:        username,
		Source:          uint32(source),
		Level:           uint32(level),
		Mobile:          mobile,
		Gender:          uint32(gender),
		ProvinceId:      uint32(provinceId),
		CityId:          uint32(cityId),
		DistrictId:      uint32(districtId),
		Status:          status,
		StartCreateTime: startCreateTime,
		EndCreateTime:   endCreateTime,
		SortField:       sortField,
		SortType:        sortType,
		Page:            uint32(page),
		PageSize:        int32(pageSize),
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(gin.H{
		"page":       result.ListResult.Page,
		"page_total": result.ListResult.PageTotal,
		"total":      result.ListResult.Total,
		"users":      result.Users,
	}))
}

/**
 * 用户详情
 *
 * @return Json
 * @author huwl
 */
func (control UserController) Detail(ctx *gin.Context) {
	uid, _ := ctx.Get("uid")
	userId, _ := strconv.ParseInt(uid.(string), 10, 64)
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	result, err := userServiceClient.UserDetail(ctx, &user.UserDetailRequest{Uid: userId})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData(gin.H{
		"user":        result.User,
		"user_albums": result.UserAlbums,
	}))
}

/**
 * 猜你喜欢的商品
 *
 * @param int uid ------------------------------必传,用户ID
 * @return Json
 * @author huwl
 */
func (control UserController) GuessLikeGoods(ctx *gin.Context) {
	// uid, _ := ctx.Get("id")
	// userId, _ := strconv.ParseInt(uid.(string), 10, 64)

	goodsList := []map[string]interface{}{}
	goodsList = append(goodsList, map[string]interface{}{
		"id":        "1",
		"goods_id":  "63",
		"cover_url": "/static/upload_images/2022-10-14/b951350101e052dba1286df8493b93b3.jpg",
		"name":      "达芙妮高跟鞋女2022年新款秋冬法式黑色职业气质设计感小众单鞋尖",
		"price":     "9900",
	})
	goodsList = append(goodsList, map[string]interface{}{
		"id":        "2",
		"goods_id":  "67",
		"cover_url": "/static/upload_images/2023-05-04/04f13c690f8a87bacbaf4cc3920486c0.jpg",
		"name":      "2023年春秋新款尖头白色金属扣真皮高跟鞋细跟气质名媛宴会单鞋女",
		"price":     "10900",
	})
	goodsList = append(goodsList, map[string]interface{}{
		"id":        "3",
		"goods_id":  "68",
		"cover_url": "/static/upload_images/2023-05-04/6c7d3a9fea6a49c0726b5c1e5b5eb28c.jpg",
		"name":      "女鞋2023新款单鞋英伦时尚个性金属方扣侧镂空尖头浅口中跟鞋显瘦",
		"price":     "10899",
	})
	goodsList = append(goodsList, map[string]interface{}{
		"id":        "4",
		"goods_id":  "70",
		"cover_url": "/static/upload_images/2023-05-10/6f1275f562c5c6c1fbbc8874a2eb94f9.jpg",
		"name":      "真皮一脚蹬白色哑光尖头高跟鞋浅口女神范细跟时尚舒适小码单鞋女",
		"price":     "19900",
	})
	control.BaseSuccess(ctx, control.WithData(gin.H{
		"guess_like_goods": goodsList,
	}))
}

/**
 * 手机找回密码发送验证码
 *
 * @param string mobile ------------------------必传,手机号
 * @return Json
 * @author huwl
 */
func (control UserController) MobileForgotPasswordSendCode(ctx *gin.Context) {
	mobile := ctx.DefaultPostForm("mobile", "")
	if mobile == "" {
		control.BaseError(ctx, control.WithMessage("请输入手机号"))
		return
	}
	if !utils.CheckMobile(mobile) {
		control.BaseError(ctx, control.WithMessage("请输入格式正确的手机号"))
		return
	}

	// 获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	_, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Mobile: mobile,
		Status: "1",
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage("手机号不存在"))
		return
	}

	// 生成、存储 验证码
	// time.Second*300 过期时间5分钟
	code := utils.CreateRandNum(100000, 400000)
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	err = ri.RedisSet("mpwd_code_"+mobile, code, time.Second*300)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 发送短信
	err = utils.SendSms(mobile, "verificationCodeTemplate", map[string]interface{}{"code": code})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("发送验证码成功"))
}

/**
 * 手机找回密码
 *
 * @param string mobile ------------------------必传,手机号
 * @param string code --------------------------必传,验证码
 * @param string new_password ------------------必传,新密码
 * @param string repassword --------------------必传,确认密码
 * @return Json
 * @author huwl
 */
func (control UserController) MobileForgotPassword(ctx *gin.Context) {
	mobile := ctx.DefaultPostForm("mobile", "")
	code := ctx.DefaultPostForm("code", "")
	newPassword := ctx.DefaultPostForm("new_password", "")
	repassword := ctx.DefaultPostForm("repassword", "")

	if mobile == "" {
		control.BaseError(ctx, control.WithMessage("请输入手机号"))
		return
	}
	if !utils.CheckMobile(mobile) {
		control.BaseError(ctx, control.WithMessage("请输入格式正确的手机号"))
		return
	}
	if code == "" {
		control.BaseError(ctx, control.WithMessage("请输入验证码"))
		return
	}
	if newPassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入新密码"))
		return
	}
	if repassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入确认密码"))
		return
	}
	if newPassword != repassword {
		control.BaseError(ctx, control.WithMessage("密码不一致"))
		return
	}

	// 判断验证码
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	redisCode, err := ri.RedisGet("mpwd_code_" + mobile)
	if err != nil {
		if err.Error() == "redis: nil" {
			control.BaseError(ctx, control.WithMessage("验证码已失效"))
			return
		}

		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	if redisCode != code {
		control.BaseError(ctx, control.WithMessage("验证码错误"))
		return
	}

	// 获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	userResult, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Mobile: mobile,
		Status: "1",
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage("手机号不存在"))
		return
	}

	// 更新密码
	_, err = userServiceClient.EditUser(ctx, &user.EditUserRequest{
		Uid:      int64(userResult.User.Uid),
		Balance:  -1,
		Password: newPassword,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 删除验证码
	err = ri.RedisDel("mpwd_code_" + mobile)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("找回密码成功"))
}

/**
 * 邮箱找回密码发送验证码
 *
 * @param string email -------------------------必传,邮箱
 * @return Json
 * @author huwl
 */
func (control UserController) EmailForgotPasswordSendCode(ctx *gin.Context) {
	email := ctx.DefaultPostForm("email", "")
	if email == "" {
		control.BaseError(ctx, control.WithMessage("请输入邮箱"))
		return
	}
	if !utils.CheckEmail(email) {
		control.BaseError(ctx, control.WithMessage("请输入格式正确的邮箱"))
		return
	}

	// 获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	_, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Email:  email,
		Status: "1",
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage("邮箱不存在"))
		return
	}

	// 生成、存储 验证码
	// time.Second*300 过期时间5分钟
	code := utils.CreateRandNum(100000, 400000)
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	err = ri.RedisSet("epwd_code_"+email, code, time.Second*300)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 发送邮件
	bodyHtml := "<html><body><p>您的验证码为 " + strconv.Itoa(code) + " ，该验证码5分钟内有效，请勿泄露于他人。</p></body></html>"

	err = utils.SendEmail(email, "找回密码", bodyHtml, "html")
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("发送验证码成功"))
}

/**
 * 邮箱找回密码
 *
 * @param string email -------------------------必传,邮箱
 * @param string code --------------------------必传,验证码
 * @param string new_password ------------------必传,新密码
 * @param string repassword --------------------必传,确认密码
 * @return Json
 * @author huwl
 */
func (control UserController) EmailForgotPassword(ctx *gin.Context) {
	email := ctx.DefaultPostForm("email", "")
	code := ctx.DefaultPostForm("code", "")
	newPassword := ctx.DefaultPostForm("new_password", "")
	repassword := ctx.DefaultPostForm("repassword", "")

	if email == "" {
		control.BaseError(ctx, control.WithMessage("请输入邮箱"))
		return
	}
	if !utils.CheckEmail(email) {
		control.BaseError(ctx, control.WithMessage("请输入格式正确的邮箱"))
		return
	}
	if code == "" {
		control.BaseError(ctx, control.WithMessage("请输入验证码"))
		return
	}
	if newPassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入新密码"))
		return
	}
	if repassword == "" {
		control.BaseError(ctx, control.WithMessage("请输入确认密码"))
		return
	}
	if newPassword != repassword {
		control.BaseError(ctx, control.WithMessage("密码不一致"))
		return
	}

	// 判断验证码
	ri, err := utils.NewRedisInstance()
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	redisCode, err := ri.RedisGet("epwd_code_" + email)
	if err != nil {
		if err.Error() == "redis: nil" {
			control.BaseError(ctx, control.WithMessage("验证码已失效"))
			return
		}

		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}
	if redisCode != code {
		control.BaseError(ctx, control.WithMessage("验证码错误"))
		return
	}

	// 获取用户信息
	userServiceClient := user.NewUserService(utils.UserServiceName, utils.MicroServer.Client())
	userResult, err := userServiceClient.Row(ctx, &user.QueryUserRequest{
		Email:  email,
		Status: "1",
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage("邮箱不存在"))
		return
	}

	// 更新密码
	_, err = userServiceClient.EditUser(ctx, &user.EditUserRequest{
		Uid:      int64(userResult.User.Uid),
		Balance:  -1,
		Password: newPassword,
	})
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	// 删除验证码
	err = ri.RedisDel("epwd_code_" + email)
	if err != nil {
		control.BaseError(ctx, control.WithMessage(err.Error()))
		return
	}

	control.BaseSuccess(ctx, control.WithData("找回密码成功"))
}
